# Copyright 2024 The Lynx Authors. All rights reserved.
# Licensed under the Apache License Version 2.0 that can be found in the
# LICENSE file in the root directory of this source tree.
import re

META_DATA_CLASS_NAME = "MetaData"

SUB_ERR_CLASS_NAME = "LynxSubErrorCode"
ERR_BEHAVIOR_CLASS_NAME = "LynxErrorBehavior"

# const for key/value in specification
KEY_METADATA = "metadata"
KEY_SECTIONS = "sections"
KEY_CODES = "codes"
KEY_BEHAVIORS = "behaviors"
KEY_TYPE = "type"
KEY_NAME = "name"
KEY_VALUES = "values"
KEY_KEYWORD = "keyword"
KEY_DEFAULT = "default"
KEY_MULTI_SELECTION = "multi-selection"
KEY_DESC = "description"
KEY_HIGH_CODE = "high-code"
KEY_MID_CODE = "mid-code"
KEY_LOW_CODE = "low-code"
VALUE_DEFAULT = "Default"
# primitive data types
TYPE_ENUM = "enum"
TYPE_STR = "string"
TYPE_NUMBER = "number"
TYPE_CHAR = "char"
TYPE_BOOL = "bool"

# define the languages that support generating error code files
LANG_JAVA = "java"
LANG_CPP = "cpp"
LANG_TS = "ts"
LANG_OC = "oc"
LANG_ETS = "ets"


ALERT_COMMENT = '''\
// !!!!!! DO NOT MODIFY THIS FILE !!!!!!
// This file is auto-generated by error_code.yaml
'''

META_DATA_DEF_BEGIN = "/** Begin define meta data for sub error code */\n"
META_DATA_DEF_END = "/** End define meta data for sub error code */\n"

CLANG_OFF = "// clang-format off\n"
CLANG_ON = "// clang-format on\n"

SECTION_COMMENT_TEMPLATE = '''
{0}/**
{0} * Section: {1}
{0} * CodePrefix: {2}
{0} * Description: {3}
{0} */\n'''

BEHAVIOR_COMMENT_TEMPLATE = '''
{0}// Behavior: {1}
{0}// Description: {2}
'''
BEHAVIOR_CODE_COMMENT_TEMPLATE = '''{0}// BehaviorCode: {1}\n\n'''

SUB_CODE_COMMENT_TEMPLATE = '''{0}// {1}\n'''

def pascal_to_upper_snake(s):
  if s == 'JavaScript':
    return 'JAVASCRIPT'
  res = []
  for i, c in enumerate(s):
    if c.isupper() and i != 0 and (s[i-1].islower() or ( i < len(s)-1 and s[i+1].islower())):
        res.append('_')
    res.append(c.upper())
  return ''.join(res)

def to_lower_snake(s):
  res = []
  for c in s:
    if c.isupper() and c != s[0]:
      res.append('_')
    res.append(c.lower())
  return ''.join(res)

def pascal_to_camel_case(s):
    if not s:
        return s
    return s[0].lower() + s[1:]

def camel_to_pascal_case(s):
    if not s:
        return s
    return s[0].upper() + s[1:]

def str_to_upper_case(s):
    ss = re.sub(r'([^A-Za-z0-9])', '_', s)
    return ss.upper()     

def is_pascal_case(s):
    pattern = re.compile("^[A-Za-z0-9]+$")
    if not bool(pattern.match(s)):
        return False
    return s[0].isalpha() and s[0].isupper()

def is_camel_case(s):
    pattern = re.compile("^[A-Za-z0-9]+$")
    if not bool(pattern.match(s)):
        return False
    return s[0].isalpha() and s[0].islower()

def is_snake_or_dash_case(s):
    return s.find('_') != -1 or s.find('-') != -1

def to_pascal_case(s):
    if is_pascal_case(s):
        return s
    if is_snake_or_dash_case(s):
        ss = s.replace('-', ' ')
        ss = ss.replace('_', ' ')
        words = ss.split()
        pascal_case = ''.join(word.capitalize() for word in words)
        return pascal_case
    return camel_to_pascal_case(s)

def to_camel_case(s):
    if is_camel_case(s):
        return s
    ss = to_pascal_case(s)
    return pascal_to_camel_case(ss)

def meta_data_value_for_sub_code(meta_data, code, behavior):
    data_keyword = meta_data[KEY_KEYWORD]
    data_value = code.get(data_keyword)
    if data_value == None:
        data_value = behavior.get(data_keyword)
    if data_value == None:
        data_value = meta_data[KEY_DEFAULT]
    return data_value